package cn.tedu.luban.settle.webapi.service.impl;

import cn.tedu.luban.account.service.IAccountService;
import cn.tedu.luban.commons.enums.settle.SettleStatusEnum;
import cn.tedu.luban.commons.enums.settle.SettleTypeEnum;
import cn.tedu.luban.commons.pojo.account.dto.PaymentDTO;
import cn.tedu.luban.commons.pojo.order.dto.OrderMqDTO;
import cn.tedu.luban.commons.pojo.settle.dto.SettleBillDTO;
import cn.tedu.luban.commons.pojo.settle.model.SettleBill;
import cn.tedu.luban.settle.service.ISettleBillService;
import cn.tedu.luban.settle.service.ISettleEventService;
import cn.tedu.luban.settle.webapi.mapper.SettleMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class SettleBillServiceImpl implements ISettleBillService {
    @DubboReference
    private IAccountService dubboAccountService;

    @Autowired
    private ISettleEventService settleEventService;

    @Autowired
    private SettleMapper settleMapper;

    @Override
    @Transactional
    public void settle(OrderMqDTO settleDTO) {
        log.info("settle方法执行");
        //先按orderNo去数据库查询settle信息
        List<SettleBill> settleBills =
                settleMapper.getSettleBillByOrderNo(settleDTO.getOrderNo());
        //如果结算记录数等于0表示没有结算
        if (settleBills.size() == 0) {
            //商家支付的金额要根据分润比例分别结算给师傅和平台
            List<SettleBillDTO> settleBillDTOs = buildSettleBillParam(settleDTO);
            //声明对应数据库表泛型类型的集合
            List<SettleBill> addSettleBills = new ArrayList<>();
            //遍历settleBillDTOs将对象转换为SettleBill类型，以完成数据库新增
            for (SettleBillDTO settleBillDTO : settleBillDTOs) {
                SettleBill settleBill = new SettleBill();
                BeanUtils.copyProperties(settleBillDTO, settleBill);
                settleBill.setRequestOrderPrice(
                        settleBillDTO.getRequestOrderRawPrice());
                settleBill.setGmtCreate(System.currentTimeMillis());
                settleBill.setGmtModified(System.currentTimeMillis());
                settleBill.setCreateUserId(99L);
                settleBill.setModifiedUserId(99L);
                settleBill.setCreateUserName("mock1");
                settleBill.setModifiedUserName("mock1");
                addSettleBills.add(settleBill);
                log.info("即将新增的结算信息为:{}", settleBill);
            }
            //执行批量新增结算信息到settle表中的操作
            settleMapper.batchInsert(addSettleBills);
            //RocketMQ发送消息，执行后续操作
            settleEventService.sendSettledEvent(settleDTO);
        }
    }

    private List<SettleBillDTO> buildSettleBillParam(OrderMqDTO settleDTO) {
        //返回值是一个List，泛型SettleBillDTO
        //这个返回值应该包含两个元素，一个是平台的结算信息，一个是师傅的
        //针对不一样的信息进行一些处理
        //获取师傅应得的金额
        Long requestOrderPrice = settleDTO.getRequestOrderPrice();
        //获取商家提供的金额
        Long requestOrderRawPrice = settleDTO.getRequestOrderRawPrice();
        //创建工人结算信息对象
        SettleBillDTO worderSettleBillDTO = buildSettleBillParam(
                settleDTO, requestOrderPrice,
                SettleTypeEnum.SETTLE_TYPE_WORKER.getStatus(),
                settleDTO.getWorkerId());
        //创建平台结算信息对象
        SettleBillDTO platformSettleBillDTO = buildSettleBillParam(settleDTO,
                //简单计算方法,直接100-80
                //requestOrderRawPrice-requestOrderPrice,
                getPlatformAmount(requestOrderRawPrice, requestOrderPrice),
                SettleTypeEnum.SETTLE_TYPE_PLATFORM.getStatus(), 999L);
        List<SettleBillDTO> settleBillDTOs = new ArrayList<>();
        settleBillDTOs.add(platformSettleBillDTO);
        settleBillDTOs.add(worderSettleBillDTO);
        return settleBillDTOs;
    }

    private SettleBillDTO buildSettleBillParam(
            OrderMqDTO settleDTO, Long amount, Integer type, Long userId) {
        SettleBillDTO settleBillDTO = new SettleBillDTO();
        BeanUtils.copyProperties(settleDTO, settleBillDTO);
        settleBillDTO.setAmount(amount);
        settleBillDTO.setType(type);
        settleBillDTO.setUserId(userId);
        settleBillDTO.setScale(settleDTO.getProfitScale());
        settleBillDTO.setRequestUserId(settleDTO.getUserId());
        settleBillDTO.setRequestUserName(settleDTO.getUserName());
        settleBillDTO.setRequestUserPhone(settleDTO.getUserPhone());
        settleBillDTO.setStatus(SettleStatusEnum.SETTLE_STATUS_WAIT.getStatus());
        settleBillDTO.setOrderGmtCreate(settleDTO.getGmtCreate());
        settleBillDTO.setTotalAmount(amount);
        return settleBillDTO;
    }

    private Long getPlatformAmount(Long rawPrice, Long workerPrice) {
        return new BigDecimal(rawPrice).subtract(
                new BigDecimal(workerPrice)).longValue();
    }

    @Override
    public void mockPayAndUpdateSettleBillStatus(OrderMqDTO orderMqDTO) {
        //要更新当前用户的余额信息
        PaymentDTO paymentDTO = new PaymentDTO();
        paymentDTO.setUserId(orderMqDTO.getWorkerId());
        paymentDTO.setOrderNo(orderMqDTO.getOrderNo());
        paymentDTO.setTotalAmount(orderMqDTO.getRequestOrderPrice());
        log.info("模拟支付信息:{}", paymentDTO);
        Long result = dubboAccountService.mockPayment(paymentDTO);
        //result是受影响的行数，大于0才进行后续操作
        if (result > 0) {
            log.info("pay success req:{},resp:{}", paymentDTO, result);
            //进行结算状态的修改
            SettleBill settleBill = new SettleBill();
            settleBill.setOrderNo(orderMqDTO.getOrderNo());
            //将结算状态新增时赋值的0(未生效)，修改为现在的1(已结算)
            settleBill.setStatus(
                    SettleStatusEnum.SETTLE_STATUS_STEELED.getStatus());
            settleBill.setPaymentTime(System.currentTimeMillis());
            settleBill.setGmtModified(System.currentTimeMillis());
            settleBill.setModifiedUserId(99L);
            settleBill.setModifiedUserName("mock");
            settleMapper.updateStatus(settleBill);
        } else {
            log.warn("账户修改余额失败:{}", paymentDTO);
        }
    }
}
